home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir40 / pm_10_94.zip / PMODE.DOC < prev    next >
Text File  |  1994-10-12  |  97KB  |  2,225 lines

  1.  
  2.   This is the documentation for PMODE 3.0 DPMI/VCPI/XMS/raw protected mode
  3. interface kernel. Copyright (c) 1994, Tran (a.k.a. Thomas Pytel). PMODE is
  4. publicly available and is not confidential or proprietary. I, Thomas Pytel,
  5. reserve all rights to the source code. However, feel free to use or distribute
  6. it in any manner you wish. All I ask, if you use this code in some production,
  7. is credits for it.
  8.  
  9. ------------------------------------------------------------------------------
  10. Contents:
  11. ---------
  12.  
  13.   0 - Introduction
  14.       0.0 - Disclaimer
  15.       0.1 - Description
  16.   1 - Overview
  17.       1.0 - Initialization and termination
  18.       1.1 - Segments, selectors, and descriptors
  19.       1.2 - Stacks and mode switching
  20.       1.3 - Interrupts
  21.       1.4 - Real mode callbacks
  22.       1.5 - PMODE specifics
  23.       1.6 - PMODE internal stacks
  24.   2 - Functions
  25.       2.0 - Function 0000h - Allocate Descriptors
  26.       2.1 - Function 0001h - Free Descriptor
  27.       2.2 - Function 0003h - Get Selector Increment Value
  28.       2.3 - Function 0006h - Get Segment Base Address
  29.       2.4 - Function 0007h - Set Segment Base Address
  30.       2.5 - Function 0008h - Set Segment Limit
  31.       2.6 - Function 0009h - Set Descriptor Access Rights
  32.       2.7 - Function 000Ah - Create Alias Descriptor
  33.       2.8 - Function 000Bh - Get Descriptor
  34.       2.9 - Function 000Ch - Set Descriptor
  35.       2.10 - Function 000Eh - Get Multiple Descriptors
  36.       2.11 - Function 000Fh - Set Multiple Descriptors
  37.       2.12 - Function 0200h - Get Real Mode Interrupt Vector
  38.       2.13 - Function 0201h - Set Real Mode Interrupt Vector
  39.       2.14 - Function 0204h - Get Protected Mode Interrupt Vector
  40.       2.15 - Function 0205h - Set Protected Mode Interrupt Vector
  41.       2.16 - Function 0300h - Simulate Real Mode Interrupt
  42.       2.17 - Function 0301h - Call Real Mode Procedure With Far Return Frame
  43.       2.18 - Function 0302h - Call Real Mode Procedure With IRET Frame
  44.       2.19 - Function 0303h - Allocate Real Mode Callback Address
  45.       2.20 - Function 0304h - Free Real Mode Callback Address
  46.       2.21 - Function 0305h - Get State Save/Restore Addresses
  47.       2.22 - Function 0306h - Get Raw Mode Switch Addresses
  48.       2.23 - Function 0400h - Get Version
  49.       2.24 - Function 0500h - Get Free Memory Information
  50.       2.25 - Function 0501h - Allocate Memory Block
  51.       2.26 - Function 0502h - Free Memory Block
  52.       2.27 - Function 0503h - Resize Memory Block
  53.       2.28 - Function 050Ah - Get Memory Block Size and Base
  54.       2.29 - Function 0900h - Get and Disable Virtual Interrupt State
  55.       2.30 - Function 0901h - Get and Enable Virtual Interrupt State
  56.       2.31 - Function 0902h - Get Virtual Interrupt State
  57.   3 - Miscellaneous
  58.       3.0 - Updates
  59.       3.1 - Glossary
  60.       3.2 - Differences among modes
  61.       3.3 - Notes
  62.       3.4 - Final word
  63.  
  64. ------------------------------------------------------------------------------
  65. 0 - Introduction:
  66. -----------------
  67.  
  68.   This document will not attempt to explain the workings of protected mode. If
  69. you are new to protected mode coding, I suggest you get yourself a good book.
  70. I also suggest you get your hands on some good DPMI documentation as a
  71. reference and background for understanding PMODE. This document is only
  72. intended to explain the workings of PMODE for the purpose of using it directly
  73. or for writing a shell or high level language interface.
  74.  
  75. 0.0 Disclaimer:
  76. ---------------
  77.  
  78. Legal:
  79.  
  80.   I exclude any and all implied warranties, including warranties of
  81. merchantability and fitness for a particular purpose. I make no warranty or
  82. representation, either express or implied, with respect to this source code,
  83. its quality, performance, merchantability, or fitness for a particular
  84. purpose. I shall have no liability for special, incidental, or consequential
  85. damages arising out of or resulting from the use or modification of this
  86. source code.
  87.  
  88. English:
  89.  
  90.   If you fuck up, its your own problem.
  91.  
  92. 0.1 Description:
  93. ----------------
  94.  
  95.   PMODE 3.0 is basically a DOS extender. It allows DOS programs to run in full
  96. protected mode. PMODE will take care of all the system details, the descriptor
  97. tables, extended memory management, interrupts, etc... It does not matter what
  98. kind of system is already in place. DPMI, VCPI, XMS, and a clean system will
  99. all be handled appropriately. If DPMI is in place, PMODE will do basically
  100. nothing, and your code will be talking directly to the DPMI host. But if it is
  101. not, PMODE will provide a subset of DPMI functionality to your code. It is
  102. slightly annoying that most of the DPMI interface uses pairs of 16bit
  103. registers for 32bit values. This goes back to the 80286 support of DPMI.
  104.  
  105.   Code using PMODE can set up its own descriptors. It can run across real
  106. mode, 16bit protected mode, and 32bit protected mode. Full extended memory
  107. management is provided. Blocks of extended memory can be allocated, resized,
  108. and freed. PMODE does not manage low memory, Your code is responsible for the
  109. memory below the 1M boundary. The PMODE kernel is well suited for a shell to
  110. extend its functionality. A shell to provide extended or simplified services
  111. to assembly or high level code.
  112.  
  113.   I wrote PMODE with attention to speed. Wherever I could control it, I tried
  114. to ensure that code using PMODE would run as fast as possible. I also tried to
  115. make sure PMODE is very stable. Under DPMI, your code is a slave to the DPMI
  116. host's whims. Almost definately running at CPL 3, which makes it quite slow.
  117. There is nothing I can do about that. Well, locating and messing with the DPMI
  118. host's system tables might not be too hard, but too unpredictable. Running in
  119. protected mode at CPL 3 is better than real mode CPL 3, because you can avoid
  120. loading segment registers very often (which is slow) by setting up flat
  121. memory. However, if DPMI is not present, you can be sure your code will be
  122. running as fast as it possibly can. Under a VCPI, XMS, or raw system, PMODE
  123. will run your code at CPL 0. There are no I/O permission bitmap checks on port
  124. accesses or task switching. Under an XMS or raw system, real mode calls are
  125. executed in actual real mode rather than the slower V86 mode, which is
  126. actually protected mode at CPL 3. Under VCPI, real mode calls are executed in
  127. V86 mode, which is what the VCPI server normally runs DOS in. Also, under
  128. VCPI, paging is enabled. It is a minor speed degredation factor, but one that
  129. is avoided under XMS or raw.
  130.  
  131.   I've been coding 386 protected mode systems for a couple of years now. I
  132. tried to make PMODE as clean as possible. But it was coded from scratch.
  133. Though I tested it extensively, there is unfortunately always the possibility
  134. of a bug. I am pretty confident it is clean though, because I went over EVERY
  135. line of code when finally done with it. I also plugged it into some old
  136. programs using a previous version of PMODE, which did well to help me find a
  137. few bugs.
  138.  
  139. ------------------------------------------------------------------------------
  140. 1 - Overview:
  141. -------------
  142.  
  143.   I adopted the DPMI interface for PMODE to make code that works with PMODE
  144. very portable to other extenders. Only a subset of DPMI is supported, both to
  145. keep the size of the kernel down, and because I am lazy (the latter being the
  146. more important factor). The interface to PMODE is INT 31h in protected mode.
  147. Functions are available for descriptors, interrupt vectors, extended memory,
  148. real mode callbacks, and calling real mode interrupts and procedures. PMODE
  149. works as a subset of DPMI 1.0 rather than DPMI 0.9. This means that error
  150. codes are returned from unsuccessful function calls, and some functions are
  151. available that are not available under DPMI 0.9. Note though, that if the
  152. system is already under DPMI 0.9, PMODE code is not active, so error codes
  153. will not be returned and only DPMI 0.9 functions will be available.
  154.  
  155. 1.0 - Initialization and termination:
  156. -------------------------------------
  157.  
  158.   There are only two functions immediately callable in PMODE. They are
  159. _pm_info and _pm_init. _pm_info returns some information about the current
  160. type of system and the low memory requirements for protected mode. No matter
  161. what the system, DPMI, VCPI, XMS, or raw, a low memory buffer is required for
  162. protected mode operation. The size of this buffer is returned from _pm_info.
  163. Your code is responsible for providing that buffer to _pm_init.
  164.  
  165.   _pm_init switches the system into protected mode. If DPMI is in place, all
  166. that is done is a switch into 32bit protected mode. If the DPMI host does not
  167. support 32bit protected mode, _pm_init will return an error. 32bit protected
  168. mode does not necessarily mean your code has to run in a 32bit segment with
  169. default 32bit instructions, it just means that it is possible. Since DPMI is
  170. defined for 80286 computers, you might even find DPMI that is capable of 32bit
  171. protected mode refusing this request on a 386 system.
  172.  
  173.   _pm_init will return with the carry flag set and an error code in AX if an
  174. error ocurred while trying to switch into protected mode. If the switch to
  175. protected mode was successful, the carry flag will be clear, and the system
  176. will be in protected mode. The CS segment register will have been converted
  177. to a protected mode selector corresponding to a descriptor mapping the same
  178. memory as it did in real mode. Likewise, the DS and SS segment registers will
  179. be converted to selectors. If DS and SS were equal before the call to
  180. _pm_init, the same selector may be returned in both. ES will contain a
  181. selector for your program's PSP. The environment segment at PSP:2ch will also
  182. be converted to a selector if it was a non-zero value before the call to
  183. _pm_init. FS and GS will be returned as 0 (NULL selector). Your code will now
  184. be running in a 16bit protected mode code segment, with full access to the
  185. protected mode INT 31h functions. If the system is DPMI, this is the last your
  186. code will have talked to PMODE, and from now on, will be using the DPMI host
  187. directly.
  188.  
  189. Both functions are FAR, and the full calling format is as follows:
  190.  
  191. ) _pm_info - Get protected mode info:
  192.   In:
  193.     None
  194.   Out:
  195.     AX - return code:
  196.       0000h - successful
  197.       0001h - no 80386+ detected
  198.       0002h - system already in protected mode and no VCPI or DPMI found
  199.       0003h - DPMI - host is not 32bit
  200.     CF - set on error, if no error:
  201.       BX - number of paragraphs needed for protected mode data (may be 0)
  202.       CL - processor type:
  203.     03h - 80386
  204.     04h - 80486
  205.     05h - 80586
  206.     06h-FFh - reserved for future use
  207.       CH - protected mode type:
  208.     00h - raw
  209.     01h - XMS
  210.     02h - VCPI
  211.     03h - DPMI
  212.  
  213. ) _pm_init - Initialize protected mode:
  214.   In:
  215.     ES - real mode segment for protected mode data (ignored if not needed)
  216.   Out:
  217.     AX - return code:
  218.       0000h - successful
  219.       0001h - no 80386+ detected
  220.       0002h - system already in protected mode and no VCPI or DPMI found
  221.       0003h - DPMI - host is not 32bit
  222.       0004h - could not enable A20 gate
  223.       0005h - DPMI - could not enter 32bit protected mode
  224.       0006h - DPMI - could not allocate needed selectors
  225.     CF - set on error, if no error:
  226.       ESP - high word clear
  227.       CS - 16bit selector for real mode CS with limit of 64k
  228.       SS - 32bit selector for real mode SS with limit of 64k
  229.       DS - 32bit selector for real mode DS with limit of 64k
  230.       ES - 32bit selector for PSP with limit of 100h
  231.       FS - 0 (NULL selector)
  232.       GS - 0 (NULL selector)
  233.  
  234.   The CS, DS, and SS selectors returned from _pm_init can be modified or
  235. freed by your code. The PSP selector and the converted environment selector in
  236. the PSP may not be. There is a special case when the CS selector returned from
  237. _pm_init may not be freed or modified. That is when the FAR CALL to _pm_init
  238. came from the PMODE_TEXT segment. In this case, PMODE will return its own code
  239. selector which maps PMODE_TEXT. This is just a minor optimization provided for
  240. any shell that has its code in PMODE_TEXT to save a descriptor.
  241.  
  242.   To terminate under PMODE, your code must issue an INT 21h function 4ch in
  243. protected mode. Just like in real mode, AL is the return code. Your code
  244. should only terminate from the main stream of execution. That is, do not try
  245. to quit from a protected mode IRQ handler or a real mode callback. Before
  246. termination, your code has the following responsibilities:
  247.  
  248. ) Restore any real mode interrupt vectors which were hooked.
  249.  
  250. ) Free any extended memory blocks that were allocated.
  251.  
  252. 1.1 - Segments, selectors, and descriptors:
  253. -------------------------------------------
  254.  
  255.   As you know (I hope), in protected mode, selectors are used in place of
  256. actual segment values in segment registers. Selectors are basically indexes
  257. into system tables which contain all the information about segments in
  258. descriptors. You can think of selectors as handles to segments. They are
  259. independent of the actual location and size of the segment in memory.
  260.  
  261.   Under PMODE, your code can allocate its own selectors and descriptors. You
  262. can set up code segments, data segments, and your own stack segments. These
  263. segments can be either 16bit, 32bit, or a mix. The best use of the flexibility
  264. of protected mode is to set up very large segments, in effect, eliminating the
  265. need for segmentation. You can set up a code descriptor, and set its size to
  266. 4G. Then a data descriptor of that same size and with the same base address.
  267. When all memory is addressable from a single segment, there is little need for
  268. other segments. But they are available, possibly for code modules to be loaded
  269. from disk into seperate segments.
  270.  
  271.   After allocating a descriptor, you code can set it up in one shot, with
  272. Set Descriptor function (000ch). Or you can set the base address, limit, and
  273. access rights/type seperately. You can also allocate a descriptor and have it
  274. automatically set to the same base address and size as another descriptor
  275. using the Create Alias Descriptor function (000ah). You code can also read a
  276. whole descriptor or base address of a descriptor. There is no Get Segment
  277. Limit function because the LSL instruction performs that function. The LAR
  278. instruction returns the access rights/type of a descriptor.
  279.  
  280.   Technically, it is possible for DPMI to deny requests to set up very large
  281. segments for protection reasons. But no DPMI host that I know of does this.
  282. They all do protection at the paging level. DPMI 1.0 specifies a function
  283. that returns an absolute ceiling for large segments. Allowing for flat memory,
  284. but falling short of the full 4G linear address range. I would not worry about
  285. this. If DPMI 1.0 hosts started to deny requests to set segment sizes to 4G,
  286. many protected mode extended programs would cease to function.
  287.  
  288.   When setting up a data descriptor which will be used as a stack segment, be
  289. aware that the B bit will determine whether PUSHes and POPs on that stack use
  290. SP or ESP as the top of stack pointer. However, even if you use a stack with
  291. the B bit clear (using SP), ESP should still be the top of stack pointer.
  292. Which means that when using a 16bit stack segment, the high word of ESP MUST
  293. be clear.
  294.  
  295. 1.2 - Stacks and mode switching:
  296. --------------------------------
  297.  
  298.   Within your main stream of execution, your code can set up its own stack.
  299. But there are times when a stack is provided to your code and your code should
  300. stay on that stack. At those times, your code may switch stacks during
  301. processing, but should return on the same stack it was called. This is during
  302. servicing of hardware interrupts or real mode callbacks in protected mode.
  303.  
  304.   Switching between protected mode and real mode can be accomplished in one of
  305. many ways. In protected mode, the default IRQ handlers switch to real mode to
  306. execute the real mode handler for the specific IRQ that was called. A software
  307. INT instruction in protected mode is also, by default, sent to on to real mode
  308. for processing. There are three specific functions which allow you to call
  309. real mode interrupts and procedures in a much more structured manner. There
  310. are real mode callbacks. These are basically addresses in real mode which,
  311. when called in real mode, transfer control to protected mode routines defined
  312. by your code. And finally, there is raw mode switching. Your code can obtain
  313. the addresses of a real mode routine which will switch the system into
  314. protected mode, and a protected mode routine which will switch the system into
  315. real mode. This is the lowest level, and quickest, method of switching modes.
  316. IRQ and INT redirection is discussed later, as are real mode callbacks.
  317.  
  318.   The INT 31h functions 0300h, 0301h, and 0302h allow your code to call real
  319. mode interrupts of FAR routines. Since protected mode selectors are not valid
  320. in real mode, your must pass the values to load into the segment registers in
  321. real mode, for the interrupt or routine, in a memory structure. This structure
  322. also contains the general registers as you want to pass them to real mode.
  323. Using these INT 31h functions, you can specify a portion of data from the
  324. protected mode stack to be put on the real mode stack for the interrupt or
  325. procedure call. You also do not have to provide a real mode stack. If you set
  326. the SS and SP fields in the register structure to 0, PMODE will provide a real
  327. mode stack for the real mode call. If you prefer, however, you can provide the
  328. stack yourself. Upon return from the real mode call, the register structure
  329. will contain the values that were passed back in the registers from the real
  330. mode interrupt handler or procedure. The CS, IP, SS, and SP fields will remain
  331. unmodified though.
  332.  
  333.   Using the raw mode switching routines is the fastest way to switch between
  334. modes. However, if these functions are to be used, special measures must be
  335. taken to preserve the state of the system. If using raw mode switching, you
  336. must use the state save/restore fuctions whose addresses you can obtain with
  337. INT 31h function 0305h. The state is saved in a buffer you provide. The stack
  338. is a good place for this buffer. Some example code is in order:
  339.  
  340. buffersize      dd      ?               ; size of state buffer
  341.  
  342. pmstate         df      ?               ; selector:offset of state routine
  343. pmtorm          df      ?               ; selector:offset of switch routine
  344.  
  345. rmstate         dd      ?               ; segment:offset of state routine
  346. rmtopm          dd      ?               ; segment:offset of switch routine
  347.  
  348. ; this code gets and stores the addresses of the various routines
  349.  
  350.         mov ax,305h                     ; get addresses of state save/restore
  351.         int 31h                         ;  routines
  352.  
  353.         movzx eax,ax                    ; zero high word of EAX
  354.         mov buffersize,eax              ; size of state buffer
  355.         mov word ptr rmstate[0],cx      ; offset of real mode state routine
  356.         mov word ptr rmstate[2],bx      ; segment of real mode state routine
  357.         mov dword ptr pmstate[0],edi    ; offset of protected mode routine
  358.         mov word ptr pmstate[4],si      ; selector of protected mode routine
  359.  
  360.         mov ax,306h                     ; get addresses of mode switch
  361.         int 31h                         ;  routines
  362.  
  363.         mov word ptr rmtopm[0],cx       ; offset of real mode switch routine
  364.         mov word ptr rmtopm[2],bx       ; segment of real mode switch routine
  365.         mov dword ptr pmtorm[0],edi     ; offset of protected mode routine
  366.         mov word ptr pmtorm[4],si       ; selector of protected mode routine
  367.  
  368. ; this code saves the state and jumps to real mode
  369.  
  370.         sub esp,buffersize              ; allocate buffer space on stack
  371.         mov edi,esp                     ; set ES:EDI = SS:ESP, buffer address
  372.         mov ax,ss
  373.         mov es,ax
  374.         xor al,al                       ; set AL = 0, save state
  375.         call pmstate                    ; save state
  376.  
  377.         mov ax,real_mode_DS_value       ; set values for real mode registers
  378.         mov cx,real_mode_ES_value
  379.         mov dx,real_mode_SS_value
  380.         mov bx,real_mode_SP_value
  381.         mov si,real_mode_CS_value
  382.         mov di,real_mode_IP_value
  383.         jmp pmtorm                      ; switch to real mode
  384.  
  385. ; this would restore the state after a return from real mode
  386.  
  387.         mov edi,esp                     ; set ES:EDI = SS:ESP, buffer address
  388.         mov ax,ss
  389.         mov es,ax
  390.         mov al,1                        ; set AL = 1, restore state
  391.         call pmstate                    ; restore state
  392.         add esp,buffersize              ; discard stack buffer space
  393.  
  394.   Real mode code to save/restore the state and call protected mode would be
  395. similar, except that EBX would be used to pass a value for ESP, and EDI would
  396. be used to pass EIP rather than IP in switching modes. Also, ES:DI would be
  397. used as the state buffer rather than ES:EDI.
  398.  
  399. 1.3 - Interrupts:
  400. -----------------
  401.  
  402.   When protected mode is first entered, all interrupts except those providing
  403. DPMI functionality are directed to a handler which will pass them on to real
  404. mode. That is, a software INT instruction executed by your code in protected
  405. mode will cause the CPU to be switched to real mode and the interrupt will be
  406. re-issued in real mode. After the interrupt handler returns, the system will
  407. be switched back to protected mode. All general registers (EAX, EBX, ECX, EDX,
  408. ESI, EDI, and EBP) in protected mode are passed on to the real mode handler,
  409. and the general registers and flags are passed back from real mode. The
  410. segment registers are not passed on to real mode since segment registers have
  411. different meanings in protected mode and real mode. This means that you can
  412. call simple interrupt routines which do not require values in segment
  413. registers, such as the keyboard BIOS function 0 to read a character from the
  414. keyboard, by just setting AH to 0 and issuing an INT 16h in protected mode. If
  415. you need to pass segment registers to a real mode interrupt handler, you must
  416. use the INT 31h function 0300h.
  417.  
  418.   IRQs are likewise passed on to real mode. PMODE will not, for the sake of a
  419. little speed increase, pass any registers to or from a real mode IRQ handler.
  420. A real DPMI host probably will pass the general registers just as it would for
  421. a software INT instruction. You may hook a protected mode interrupt vector for
  422. any interrupt, 0-0ffh, and process the interrupt entirely in protected mode if
  423. you wish. Or you can do some processing in protected mode, then chain to the
  424. real mode handler by passing control to the previous handler for the interrupt
  425. your code hooked.
  426.  
  427.   If an IRQ occurs in real mode, by default, it will not be passed on to its
  428. protected mode handler. Rather, it will go directly to its real mode handler.
  429. Under a real DPMI host, the IRQ will probably be sent on to its protected mode
  430. handler first. If you wish send IRQs that occur in real mode to a protected
  431. mode handler, set up a real mode callback for that interrupt vector. Or faster
  432. than that, install your own real mode routine which will switch to your
  433. protected mode code using the raw mode switching routines.
  434.  
  435.   PMODE will provide a real mode stack for both the software INT redirection
  436. and the hardware IRQ redirection to real mode. If a real mode stack is
  437. unavailable because of too many nested calls to real mode, the PC speaker will
  438. be turned on and the machine will be hung. I prefer this to clunky exception
  439. code messing up my nice and pretty extender.
  440.  
  441.   In protected mode, when interrupt handlers are called, the interrupt flag is
  442. not disabled like it is in real mode. This is done only for IRQs and
  443. interrupts 0-7. Handlers for all other interrupts in protected mode must not
  444. assume the interrupt flag has been cleared for them. If they need interrupts
  445. disabled, they must do it themselves.
  446.  
  447.   Under DPMI, the interrupt flag may need to be virtualized. I will spare you
  448. a long explanation because any good DPMI text will give that to you. But I
  449. will give you some rules:
  450.  
  451. ) You must not assume anything about instructions that would normally affect
  452.   the interrupt flag. Instructions like POPF and IRETD may have no effect on
  453.   the current status of the interrupt flag. Also, PUSHF or an INT may not
  454.   store the interrupt flag correctly, so do not trust them to get information
  455.   on the interrupt flag.
  456.  
  457. ) The only things you can be sure will affect the interrupt flag are CLI, STI,
  458.   and INT 31h functions 0900h and 0901h.
  459.  
  460. ) If you need to learn the current status of the interrupt flag, you must use
  461.   one of the INT 31h functions, 0900h to clear and get the status of the
  462.   interrupt flag, 0901h to set and get the status of the flag, or 0902h which
  463.   simply returns the current value of the interrupt flag.
  464.  
  465. ) Since IRETD may not affect the interrupt flag, you should re-enable
  466.   interrupts in a protected mode IRQ handler. This is because the interrupt
  467.   flag will have been cleared upon entry to the handler.
  468.  
  469.   When writing interrupt handlers, you must terminate them with an IRETD, not
  470. a simple IRET. For hardware IRQ handlers, you may want to make sure that any
  471. code and data that may be touched by the IRQ handler resides in low memory,
  472. below 1M. This memory is locked under DPMI, and will prevent having to swap
  473. from disk at interrupt time under DPMI hosts which support virtual memory. One
  474. other thing you should remember about IRQ handlers. IRQ 2 is really IRQ 9.
  475. Devices which say they use IRQ 2 are actually using IRQ 9. In real mode, the
  476. BIOS handler for IRQ 9 redirects it to the handler for IRQ 2. There is no such
  477. redirection done in protected mode. So if you wish to write a handler for
  478. IRQ 2 in protected mode, you must put it on IRQ 9. And remember to send the
  479. EOI to the second interrupt controller. The BIOS IRQ 9 handler does that, but
  480. you don't have the BIOS anymore.
  481.  
  482. 1.4 - Real mode callbacks:
  483. --------------------------
  484.  
  485.   Real mode callbacks allow code running in real mode to call protected mode
  486. procedures in a transparent manner. The real mode code thinks it is passing
  487. control to another real mode procedure. This is, in reality, a real mode
  488. callback. Which is basically a small routine which stores the values of the
  489. real mode registers in a structure, then switches to protected mode and passes
  490. control to a protected mode routine you specify.
  491.  
  492.   Callbacks are allocated and freed just like descriptors or memory. When
  493. allocating a callback, your code specifies the address of the protected mode
  494. routine that is to gain control when the real mode callback is called. You
  495. must also specify the selector:offset of a memory structure that is to recieve
  496. the contents of the registers in real mode. The format of this structure is
  497. the same as for INT 31h functions 0300h, 0301h, and 0302h. When the protected
  498. mode routine for a real mode callback gets control, interrupts will be
  499. disabled, and the following registers are defined:
  500.  
  501.   DS:ESI - selector:offset corresponding to real mode SS:SP
  502.   ES:EDI - selector:offset of real mode register data structure
  503.   SS:ESP - protecterd mode stack provided by PMODE or the DPMI host
  504.  
  505. The real mode register data structure has the following format:
  506.  
  507.   Offset  Length  Contents
  508.   00h     4       EDI
  509.   04h     4       ESI
  510.   08h     4       EBP
  511.   0ch     4       reserved, ignored
  512.   10h     4       EBX
  513.   14h     4       EDX
  514.   18h     4       ECX
  515.   1ch     4       EAX
  516.   20h     2       CPU status flags
  517.   22h     2       ES
  518.   24h     2       DS
  519.   26h     2       FS
  520.   28h     2       GS
  521.   2ah     2       IP, undefined
  522.   2ch     2       CS, undefined
  523.   2eh     2       SP
  524.   30h     2       SS
  525.  
  526.   All fields except the CS and IP are filled in with the contents of the real
  527. mode registers when the real mode callback got control. The protected mode
  528. callback procedure can extract its parameters from the register data structure
  529. and/or the real mode stack. Remember that the segment registers contain real
  530. mode segment addresses, not protected mode selectors.
  531.  
  532.   The protected mode callback procedure exits with an IRETD with the address
  533. of the real mode register data structure in ES:EDI. Information can be passed
  534. back to real mode by modifying the contents of the register data structure and
  535. the real mode stack. The protected mode callback routine is responsible for
  536. setting the correct address for the resumption of execution in real mode in
  537. the CS:IP fields of the register data structure. It is also responsible for
  538. updating the SS:SP fields in the register data structure to remove the address
  539. of the calling real mode routine from the real mode stack.
  540.  
  541.   The real mode register data structure and the DS selector used to map the
  542. real mode SS segment are static. This is not a problem if you leave interrupts
  543. disabled throughout the protected mode callback routine. But if you intend to
  544. re-enable interrupts, you must make sure you do not use the DS selector
  545. anymore. If you need to access the real mode stack after enabling interrupts,
  546. you must create an alias descriptor for the DS selector passed to your
  547. callback procedure. Or you can take other measures, but just remember that the
  548. original DS selector is no longer safe after enabling interrupts in a
  549. protected mode callback routine.
  550.  
  551.   Since the real mode register data structure is also static, you should take
  552. special care if you wish to enable interrupts in a callback. Since the data
  553. structure is needed for the exit from the callback, you can not simply
  554. discard it. You should make a copy of the data structure. You can then pass
  555. back the copy when you exit the callback procedure. The ES:EDI upon exit is
  556. not required to be the same as on entry.
  557.  
  558. 1.5 - PMODE specifics:
  559. ----------------------
  560.  
  561.   PMODE makes several variables public. These control certain things when
  562. running under VCPI, XMS, or a raw system. Under DPMI, these variables do
  563. absolutely nothing. The size of the low memory protected mode buffer required
  564. for _pm_init is directly affected by these variables. Thus, they must be set
  565. to the same values for the call to _pm_info and _pm_init. You should only
  566. modify these variables before switching into protected mode.
  567.  
  568. ) _pm_pagetables - This specifies the number of page tables you want to have
  569.   under VCPI. Each page table requires 4k and maps 4M of linear memory. Page
  570.   tables only define linear address space, not actual physical memory. The
  571.   amount of extended memory that will be available to your code will be the
  572.   lesser of linear and physical memory in the system. Setting a higher number
  573.   of page tables will not give you any more physical memory than is available
  574.   in the system, but it will give you more linear address space where physical
  575.   memory can be mapped. This helps reduce fragmentation of memory when
  576.   allocating extended memory blocks under VCPI. Never set this variable to 0,
  577.   since the first page table maps the low megabyte of real mode memory.
  578.  
  579. ) _pm_selectors - This is the total number of descriptors you want PMODE to
  580.   make available to your code for allocation. The range for this variable is
  581.   0 to about 8150. The actual max number of descriptors that can exist in the
  582.   global descriptor table, which is where descriptors under PMODE reside, is
  583.   8191. But some of these descriptors are used by PMODE. Also, DPMI may not
  584.   be able to provide quite as many as 8000 descriptors. Each descriptor takes
  585.   up 8 bytes of space in the low memory protected mode buffer.
  586.  
  587. ) _pm_callbacks - This is the number of real mode callbacks you want PMODE to
  588.   provide for allocation. Each callback takes up 25 bytes of space. You may
  589.   set this variable to 0.
  590.  
  591. ) _pm_rmstacklen - This is the size of the real mode stack, in paragraphs,
  592.   that is provided for IRQ and INT redirection to real mode. Also for INT 31h
  593.   functions 0300h, 0301h, and 0302h when the SS:SP field in the register
  594.   structure is zero.
  595.  
  596. ) _pm_rmstacks - This is the number of real mode stacks you want present in
  597.   case of nested calls to real mode. There must be at least one.
  598.  
  599. ) _pm_pmstacklen - This is the size of the protected mode stack, in
  600.   paragraphs, to provide for protected mode procedures which handle real mode
  601.   callbacks.
  602.  
  603. ) _pm_pmstacks - This is the number of protected mode stacks you want present
  604.   in case of nested callbacks. If your code is not going to be using real mode
  605.   callbacks, you may set this variable, along with _pm_pmstacklen and
  606.   _pm_callbacks, to zero.
  607.  
  608. 1.6 - PMODE internal stacks:
  609. ----------------------------
  610.  
  611.   The memory space of the real mode and protected mode stacks used by PMODE
  612. for INT and IRQ redirection and callbacks can be used by your code if you do
  613. your own raw mode switching and need stack space. This is just a minor memory
  614. optimization, especially useful if you will have many nested mode switches
  615. using PMODE and raw mode services. These memory areas are only available under
  616. a VCPI/XMS/raw system. If a DPMI host is already in place, PMODE is not in
  617. control and does not have these memory areas to share with your code, in which
  618. case you will have to allocate any stack buffers you need yourself anyway.
  619.  
  620.   All of PMODE except this is the standard DPMI interface. If you use this
  621. technique I can not guarantee support in future major revisions of PMODE, nor
  622. can you be sure of 'portability' to other extenders. On the other hand, if you
  623. use this method, you will have to handle setting up your own stack buffers
  624. anyway if the system is running under a DPMI host. This will make your code
  625. 'portable' since, if ever you move it, you have the stack buffer code right
  626. there. The reason I make this option available in PMODE, is that for a while
  627. now, multiple nested stack areas for PMODE and any external shell for it have
  628. bothered me as an unnecessary waste of memory.
  629.  
  630.   The memory areas of the stacks are defined by four variables made public in
  631. the PMODE segment. They define the base and current top of the entire real
  632. mode and protected mode stack areas (all nested stacks for each mode). The
  633. protected mode base and top are dword pointers relative to the beginning of
  634. memory (0000:0000). The real mode base and top are real mode segment word
  635. values. The tops of the stacks are all that you really need to use the stack
  636. areas, the bases are provided in case you want to check for running out of
  637. nested stacks. The four variables are as follows:
  638.  
  639. ) pmstacktop - This is the linear address of the current top of the protected
  640.   mode stack area.
  641.  
  642. ) pmstackbase - This is the linear base address of the entire protected mode
  643.   stack area. If ever the value of pmstacktop drops below this value, you ran
  644.   out of memory in the protected mode stack buffer.
  645.  
  646. ) rmstacktop - This is the real mode segment value of the current top of the
  647.   real mode stack area.
  648.  
  649. ) rmstackbase - This is the real mode segment value of the base of the real
  650.   mode stack area. Again, if the value of rmstacktop falls below this value,
  651.   you are out of real mode stack buffer memory. This does not necessarily mean
  652.   death, since you would be accessing this before you actually switch to real
  653.   mode, it simply means there is not enough room in the PMODE stack buffers
  654.   to switch to real mode.
  655.  
  656.   The size of the entire real and protected mode stack areas is defined when
  657. you enter protected mode by the variables _pm_rmstacklen, _pm_rmstacks,
  658. _pm_pmstacklen, _pm_pmstacks. The real mode stack area is the one used by
  659. PMODE for INT and IRQ redirection, and INT 31h functions 0300h, 0301h, and
  660. 0302h, and its entire size in bytes is _pm_rmstacklen * _pm_rmstacks * 16. The
  661. protected mode stack area is the one used by callbacks and its size is
  662. _pm_pmstacklen * _pm_pmstacks * 16. This means that if you intend to use the
  663. PMODE protected mode stacks, you must make them available through
  664. _pm_pmstacklen and _pm_pmstacks even if you do not use real mode callbacks.
  665. These stack areas are used from the top to bottom as nested mode stacks are
  666. allocated.
  667.  
  668. An example of use:
  669.  
  670. ; this code loads DX:BX with a valid real mode SS:SP for a raw mode switch
  671. ; to real mode assuming DS is a selector mapping the PMODE segment PMODE_TEXT
  672.  
  673.         mov dx,rmstacktop               ; DX = current real mode stack top
  674.         mov bx,_pm_rmstacklen           ; BX = length of PMODE real mode stack
  675.         sub dx,bx                       ; subtract size of stack from top
  676.  
  677.         cmp dx,rmstackbase              ; check if ran out of memory
  678.         jb ran_out_of_RM_stack_memory
  679.  
  680.         mov rmstacktop,dx               ; put the adjusted value back
  681.         shl bx,4                        ; adjust stack len from para to bytes
  682.  
  683. ; DX:BX now contains the real mode segment:offset of a valid real mode stack
  684. ; as could be used by the raw mode switching services, after the return from
  685. ; real mode you must remember to adjust the current stack top
  686.  
  687.         mov ax,_pm_rmstacklen           ; AX = length of real mode stack
  688.         add rmstacktop,ax               ; readjust real mode stack top
  689.  
  690. ; this code loads DX:EBX with a valid protected mode SS:ESP for a raw mode
  691. ; switch to protected mode assuming DS is PMODE_TEXT
  692.  
  693.         mov ebx,pmstacktop              ; EBX = current protected stack top
  694.         mov ecx,ebx                     ; ECX = EBX for adjust
  695.         mov eax,_pm_pmstacklen          ; EAX = length of protected mode stack
  696.         shl eax,4                       ; convert length from para to bytes
  697.         sub ecx,eax                     ; subtract size of stack from top
  698.  
  699.         cmp ecx,pmstackbase             ; check if ran out of memory
  700.         jb ran_out_of_PM_stack_memory
  701.  
  702.         mov pmstacktop,ecx              ; put the adjusted value back
  703.  
  704. ; EBX now contains the top of a valid protected mode stack area relative to
  705. ; the beginning of memory, you must still load up DX with a valid protected
  706. ; mode SS and adjust EBX by the base address of that selector to convert it
  707. ; to a valid ESP relative to the base of the stack segment
  708.  
  709.         mov dx,PM_stack_selector        ; DX = SS selector for protected mode
  710.         sub ebx,PM_stack_selector_base  ; adjust EBX for a valid ESP
  711.  
  712. ; and ofcourse after the return from protected mode readjust the stack top
  713.  
  714.         mov eax,_pm_pmstacklen          ; EAX = length of protected mode stack
  715.         shl eax,4                       ; convert length from para to bytes
  716.         add pmstacktop,eax              ; readjust protected mode stack top
  717.  
  718.   You do not have to use _pm_rmstacklen and _pm_pmstacklen for the size of the
  719. stacks you allocate from the stack memory, but you should keep the sizes at
  720. least a dword multiple. Also do not make the stacks too small, at least 128
  721. bytes is a good minimum value.
  722.  
  723.   As I said, under a real DPMI host, PMODE does not initialize these stack
  724. memory areas. Your code would have to do it on its own. But you can use the
  725. same variables to store the base and top of the stack memory areas your code
  726. allocates since PMODE will not be using them as it will not be in control.
  727. This means you can use the same code for raw mode switching and mode stack
  728. allocation. All that will be required is some code at protected mode init time
  729. that will allocate some memory for the stack areas and store their base and
  730. top in the respective variables.
  731.  
  732. ------------------------------------------------------------------------------
  733. 2 - Functions:
  734. --------------
  735.  
  736.   PMODE duplicates a subset of DPMI protected mode functions. These functions
  737. are available ONLY in protected through INT 31h. They provide descriptor
  738. services, extended memory services, interrupt services, translation services,
  739. and some other misc things. A function is called by setting AX to the function
  740. code, setting any other registers for the function, and executing an INT 31h.
  741. Upon return, the carry flag will be clear if the function was successful. If
  742. the carry flag is set, the function failed. In this case, an error code will
  743. be placed in AX. However, DPMI 0.9 will not return error codes, just the carry
  744. flag set on errors. All other registers are preserved unless otherwise stated.
  745.  
  746. 2.0 - Function 0000h - Allocate Descriptors:
  747. --------------------------------------------
  748.  
  749. Allocates one or more descriptors in the client's descriptor table. The
  750. descriptor(s) allocated must be initialized by the application with other
  751. function calls.
  752.  
  753. In:
  754.   AX     = 0000h
  755.   CX     = number of descriptors to allocate
  756.  
  757. Out:
  758.   if successful:
  759.   AX     = base selector
  760.  
  761.   if failed:
  762.   AX     = error code:
  763.            8011h - descriptor unavailable
  764.            8021h - invalid value (CX = 0) (VCPI/XMS/raw only)
  765.  
  766. Notes:
  767. ) If more that one descriptor was requested, the function returns a base
  768.   selector referencing the first of a contiguous array of descriptors. The
  769.   selector values for subsequent descriptors in the array can be calculated
  770.   by adding the value returned by INT 31h function 0003h.
  771.  
  772. ) The allocated descriptor(s) will be set to expand-up writeable data, with
  773.   the present bit set and a base and limit of zero. The privilege level of the
  774.   descriptor(s) will match the client's code segment privilege level.
  775.  
  776. 2.1 - Function 0001h - Free Descriptor:
  777. ---------------------------------------
  778.  
  779. Frees a descriptor.
  780.  
  781. In:
  782.   AX     = 0001h
  783.   BX     = selector for the descriptor to free
  784.  
  785. Out:
  786.   if failed:
  787.   AX     = error code:
  788.            8022h - invalid selector
  789.  
  790. Notes:
  791. ) Each descriptor allocated with INT 31h function 0000h must be freed
  792.   individually with the function. Even if it was previously allocated as part
  793.   of a contiguous array of descriptors.
  794.  
  795. ) Under DPMI 1.0/VCPI/XMS/raw, any segment registers which contain the
  796.   selector being freed are zeroed by this function.
  797.  
  798. 2.2 - Function 0003h - Get Selector Increment Value:
  799. ----------------------------------------------------
  800.  
  801. The Allocate Descriptors function (0000h) can allocate an array of contiguous
  802. descriptors, but only return a selector for the first descriptor. The value
  803. returned by this function can be used to calculate the selectors for
  804. subsequent descriptors in the array.
  805.  
  806. In:
  807.   AX     = 0003h
  808.  
  809. Out:
  810.   always successful:
  811.   AX     = selector increment value
  812.  
  813. Notes:
  814. ) The increment value is always a power of two.
  815.  
  816. 2.3 - Function 0006h - Get Segment Base Address:
  817. ------------------------------------------------
  818.  
  819. Returns the 32bit linear base address from the descriptor table for the
  820. specified segment.
  821.  
  822. In:
  823.   AX     = 0006h
  824.   BX     = selector
  825.  
  826. Out:
  827.   if successful:
  828.   CX:DX  = 32bit linear base address of segment
  829.  
  830.   if failed:
  831.   AX     = error code:
  832.            8022h - invalid selector
  833.  
  834. Notes:
  835. ) Client programs must use the LSL instruction to query the limit for a
  836.   descriptor.
  837.  
  838. 2.4 - Function 0007h - Set Segment Base Address:
  839. ------------------------------------------------
  840.  
  841. Sets the 32bit linear base address field in the descriptor for the specified
  842. segment.
  843.  
  844. In:
  845.   AX     = 0007h
  846.   BX     = selector
  847.   CX:DX  = 32bit linear base address of segment
  848.  
  849. Out:
  850.   if failed:
  851.   AX     = error code:
  852.            8022h - invalid selector
  853.            8025h - invalid linear address (changing the base would cause the
  854.                    descriptor to reference a linear address range outside that
  855.                    allowed for DPMI clients) (DPMI 1.0 only)
  856.  
  857. Notes:
  858. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  859.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  860.   but it is not guaranteed.
  861.  
  862. ) I hope you have enough sense not to try to modify your current CS or SS
  863.   descriptor.
  864.  
  865. 2.5 - Function 0008h - Set Segment Limit:
  866. -----------------------------------------
  867.  
  868. Sets the limit field in the descriptor for the specified segment.
  869.  
  870. In:
  871.   AX     = 0008h
  872.   BX     = selector
  873.   CX:DX  = 32bit segment limit
  874.  
  875. Out:
  876.   if failed:
  877.   AX     = error code:
  878.            8021h - invalid value (the limit is > 1M, but the low 12 bits are
  879.                    not set)
  880.            8022h - invalid selector
  881.            8025h - invalid linear address (changing the base would cause the
  882.                    descriptor to reference a linear address range outside that
  883.                    allowed for DPMI clients) (DPMI 1.0 only)
  884.  
  885. Notes:
  886. ) The value supplied to the function in CX:DX is the byte length of the
  887.   segment-1.
  888.  
  889. ) Segment limits greater than or equal to 1M must be page aligned. That is,
  890.   they must have the low 12 bits set.
  891.  
  892. ) This function has an implicit effect on the "G" bit in the segment's
  893.   descriptor.
  894.  
  895. ) Client programs must use the LSL instruction to query the limit for a
  896.   descriptor.
  897.  
  898. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  899.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  900.   but it is not guaranteed.
  901.  
  902. ) I hope you have enough sense not to try to modify your current CS or SS
  903.   descriptor.
  904.  
  905. 2.6 - Function 0009h - Set Descriptor Access Rights:
  906. ----------------------------------------------------
  907.  
  908. Modifies the access rights field in the descriptor for the specified segment.
  909.  
  910. In:
  911.   AX     = 0009h
  912.   BX     = selector
  913.   CX     = access rights/type word
  914.  
  915. Out:
  916.   if failed:
  917.   AX     = error code:
  918.            8021h - invalid value (access rights/type word invalid)
  919.            8022h - invalid selector
  920.            8025h - invalid linear address (changing the base would cause the
  921.                    descriptor to reference a linear address range outside that
  922.                    allowed for DPMI clients) (DPMI 1.0 only)
  923.  
  924. Notes:
  925. ) The access rights/type word passed to the function in CX has the following
  926.   format:
  927.  
  928.     Bit: 15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  929.        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  930.        | G |B/D| 0 | ? |       ?       | 1 |  DPL  | 1 |C/D|E/C|W/R| A |
  931.        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  932.  
  933.     G   - 0=byte granular, 1=page granular
  934.     B/D - 0=default 16bit, 1=default 32bit
  935.     DPL - must be equal to caller's CPL
  936.     C/D - 0=data, 1=code
  937.     E/C - data: 0=expand-up, 1=expand-down
  938.           code: must be 0 (non-conforming)
  939.     W/R - data: 0=read, 1=read/write
  940.           code: must be 1 (readable)
  941.     A   - 0=not accessed, 1=accessed
  942.     0   - must be 0
  943.     1   - must be 1
  944.     ?   - ignored
  945.  
  946. ) Client programs should use the LAR instruction to examine the access rights
  947.   of a descriptor.
  948.  
  949. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  950.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  951.   but it is not guaranteed.
  952.  
  953. ) I hope you have enough sense not to try to modify your current CS or SS
  954.   descriptor.
  955.  
  956. 2.7 - Function 000Ah - Create Alias Descriptor:
  957. -----------------------------------------------
  958.  
  959. Creates a new data descriptor that has the same base and limit as the
  960. specified descriptor.
  961.  
  962. In:
  963.   AX     = 000ah
  964.   BX     = selector
  965.  
  966. Out:
  967.   if successful:
  968.   AX     = data selector (alias)
  969.  
  970.   if failed:
  971.   AX     = error code:
  972.            8011h - descriptor unavailable
  973.            8022h - invalid selector
  974.  
  975. Notes:
  976. ) The selector supplied to the function may be either a data descriptor or
  977.   a code descriptor. The alias descriptor created is always an expand-up
  978.   writeable data segment.
  979.  
  980. ) The descriptor alias returned by this function will not track changes to the
  981.   original descriptor.
  982.  
  983. 2.8 - Function 000Bh - Get Descriptor:
  984. --------------------------------------
  985.  
  986. Copies the descriptor table entry for the specified selector into an 8 byte
  987. buffer.
  988.  
  989. In:
  990.   AX     = 000bh
  991.   BX     = selector
  992.   ES:EDI = selector:offset of 8 byte buffer
  993.  
  994. Out:
  995.   if successful:
  996.   buffer pointed to by ES:EDI contains descriptor
  997.  
  998.   if failed:
  999.   AX     = error code:
  1000.            8022h - invalid selector
  1001.  
  1002. 2.9 - Function 000Ch - Set Descriptor:
  1003. --------------------------------------
  1004.  
  1005. Copies the contents of an 8 byte buffer into the descriptor for the specified
  1006. selector.
  1007.  
  1008. In:
  1009.   AX     = 000ch
  1010.   BX     = selector
  1011.   ES:EDI = selector:offset of 8 byte buffer containing descriptor
  1012.  
  1013. Out:
  1014.   if failed:
  1015.   AX     = error code:
  1016.            8021h - invalid value (access rights/type word invalid)
  1017.            8022h - invalid selector
  1018.            8025h - invalid linear address (changing the base would cause the
  1019.                    descriptor to reference a linear address range outside that
  1020.                    allowed for DPMI clients) (DPMI 1.0 only)
  1021.  
  1022. ) The descriptors access rights/type word at offset 5 within the descriptor
  1023.   follows the same format and restrictions as the access rights/type parameter
  1024.   CX to the Set Descriptor Access Rights function (0009h).
  1025.  
  1026. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  1027.   selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  1028.   but it is not guaranteed.
  1029.  
  1030. ) I hope you have enough sense not to try to modify your current CS or SS
  1031.   descriptor or the descriptor of the buffer.
  1032.  
  1033. 2.10 - Function 000Eh - Get Multiple Descriptors:
  1034. -------------------------------------------------
  1035.  
  1036. Copies one or more descriptor table entries into a buffer.
  1037.  
  1038. In:
  1039.   AX     = 000eh
  1040.   CX     = number of descriptors to copy
  1041.   ES:EDI = selector:offset of a buffer in the following format:
  1042.  
  1043.            Offset  Length  Contents
  1044.            00h     2       Selector #1 (set by client)
  1045.            02h     8       Descriptor #1 (returned by host)
  1046.            0ah     2       Selector #2 (set by client)
  1047.            0ch     8       Descriptor #2 (returned by host)
  1048.            ...     ...     ...
  1049.  
  1050. Out:
  1051.   if successful:
  1052.   buffer contains copies of the descriptors for the specified selectors
  1053.  
  1054.   if failed:
  1055.   AX     = error code:
  1056.            8022h - invalid selector
  1057.   CX     = number of descriptors successfully copied
  1058.  
  1059. Notes:
  1060. ) If an error occurs because of an invalid selector or descriptor, the
  1061.   function returns the number of descriptors which were successfully copied
  1062.   in CX. All of the descriptors which were copied prior to the one that failed
  1063.   are valid.
  1064.  
  1065. ) This function is not present under DPMI 0.9.
  1066.  
  1067. 2.11 - Function 000Fh - Set Multiple Descriptors:
  1068. -------------------------------------------------
  1069.  
  1070. Copies one or more descriptors from a client buffer into the descriptor table.
  1071.  
  1072. In:
  1073.   AX     = 000fh
  1074.   CX     = number of descriptors to copy
  1075.   ES:EDI = selector:offset of a buffer in the following format:
  1076.  
  1077.            Offset  Length  Contents
  1078.            00h     2       Selector #1
  1079.            02h     8       Descriptor #1
  1080.            0ah     2       Selector #2
  1081.            0ch     8       Descriptor #2
  1082.            ...     ...     ...
  1083.  
  1084. Out:
  1085.   if failed:
  1086.   AX     = error code:
  1087.            8021h - invalid value (access rights/type word invalid)
  1088.            8022h - invalid selector
  1089.            8025h - invalid linear address (changing the base would cause the
  1090.                    descriptor to reference a linear address range outside that
  1091.                    allowed for DPMI clients) (DPMI 1.0 only)
  1092.   CX     = number of descriptors successfully copied
  1093.  
  1094. Notes:
  1095. ) If an error occurs because of an invalid selector or descriptor, the
  1096.   function returns the number of descriptors which were successfully copied in
  1097.   CX. All of the descriptors which were copied prior to the one that failed
  1098.   are valid.
  1099.  
  1100. ) The descriptors access rights/type word at offset 5 within the descriptor
  1101.   follows the same format and restrictions as the access rights/type parameter
  1102.   CX to the Set Descriptor Access Rights (0009h) function.
  1103.  
  1104. ) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains a selector
  1105.   specified in the data structure will be reloaded. DPMI 0.9 may do this,
  1106.   but it is not guaranteed.
  1107.  
  1108. ) I hope you have enough sense not to try to modify your current CS or SS
  1109.   descriptor or the descriptor of the buffer.
  1110.  
  1111. ) This function is not present under DPMI 0.9.
  1112.  
  1113. 2.12 - Function 0200h - Get Real Mode Interrupt Vector:
  1114. -------------------------------------------------------
  1115.  
  1116. Returns the real mode segment:offset for the specified interrupt vector.
  1117.  
  1118. In:
  1119.   AX     = 0200h
  1120.   BL     = interrupt number
  1121.  
  1122. Out:
  1123.   always successful:
  1124.   CX:DX  = segment:offset of real mode interrupt handler
  1125.  
  1126. Notes:
  1127. ) The value returned in CX is a real mode segment address, not a protected
  1128.   mode selector.
  1129.  
  1130. 2.13 - Function 0201h - Set Real Mode Interrupt Vector:
  1131. -------------------------------------------------------
  1132.  
  1133. Sets the real mode segment:offset for the specified interrupt vector.
  1134.  
  1135. In:
  1136.   AX     = 0201h
  1137.   BL     = interrupt number
  1138.   CX:DX  = segment:offset of real mode interrupt handler
  1139.  
  1140. Notes:
  1141. ) The value passed in CX must be a real mode segment address, not a protected
  1142.   mode selector. Consequently, the interrupt handler must either reside in
  1143.   DOS memory (below the 1M boundary) or the client must allocate a real mode
  1144.   callback address.
  1145.  
  1146. 2.14 - Function 0204h - Get Protected Mode Interrupt Vector:
  1147. ------------------------------------------------------------
  1148.  
  1149. Returns the address of the current protected mode interrupt handler for the
  1150. specified interrupt.
  1151.  
  1152. In:
  1153.   AX     = 0204h
  1154.   BL     = interrupt number
  1155.  
  1156. Out:
  1157.   always successful:
  1158.   CX:EDX = selector:offset of protected mode interrupt handler
  1159.  
  1160. Notes:
  1161. ) The value returned in CX is a valid protected mode selector, not a real mode
  1162.   segment address.
  1163.  
  1164. 2.15 - Function 0205h - Set Protected Mode Interrupt Vector:
  1165. ------------------------------------------------------------
  1166.  
  1167. Sets the address of the protected mode interrupt handler for the specified
  1168. interrupt.
  1169.  
  1170. In:
  1171.   AX     = 0205h
  1172.   BL     = interrupt number
  1173.   CX:EDX = selector offset of protected mode interrupt handler
  1174.  
  1175. Out:
  1176.   if failed:
  1177.   AX     = error code:
  1178.            8022h - invalid selector
  1179.  
  1180. Notes:
  1181. ) The value passed in CX must be a valid protected mode selector, not a real
  1182.   mode segment address.
  1183.  
  1184. 2.16 - Function 0300h - Simulate Real Mode Interrupt:
  1185. -----------------------------------------------------
  1186.  
  1187. Simulates an interrupt in real mode. The function transfers control to the
  1188. address specified by the real mode interrupt vector. The real mode handler
  1189. must return by executing an IRET.
  1190.  
  1191. In:
  1192.   AX     = 0300h
  1193.   BL     = interrupt number
  1194.   BH     = must be 0
  1195.   CX     = number of words to copy from the protected mode stack to the real
  1196.            mode stack
  1197.   ES:EDI = selector:offset of real mode register data structure in the
  1198.            following format:
  1199.  
  1200.            Offset  Length  Contents
  1201.            00h     4       EDI
  1202.            04h     4       ESI
  1203.            08h     4       EBP
  1204.            0ch     4       reserved, ignored
  1205.            10h     4       EBX
  1206.            14h     4       EDX
  1207.            18h     4       ECX
  1208.            1ch     4       EAX
  1209.            20h     2       CPU status flags
  1210.            22h     2       ES
  1211.            24h     2       DS
  1212.            26h     2       FS
  1213.            28h     2       GS
  1214.            2ah     2       IP (reserved, ignored)
  1215.            2ch     2       CS (reserved, ignored)
  1216.            2eh     2       SP
  1217.            30h     2       SS
  1218.  
  1219. Out:
  1220.   if successful:
  1221.   ES:EDI = selector offset of modified real mode register data structure
  1222.  
  1223.   if failed:
  1224.   AX     = error code:
  1225.            8012h - linear memory unavailable (stack)
  1226.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1227.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1228.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1229.  
  1230. Notes:
  1231. ) The CS:IP in the real mode register data structure is ignored by this
  1232.   function. The appropriate interrupt handler will be called based on the
  1233.   value passed in BL.
  1234.  
  1235. ) If the SS:SP fields in the real mode register data structure are zero, a
  1236.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1237.   will be set to the specified values before the interrupt handler is called.
  1238.  
  1239. ) The flags specified in the real mode register data structure will be put on
  1240.   the real mode interrupt handler's IRET frame. The interrupt handler will be
  1241.   called with the interrupt and trace flags clear.
  1242.  
  1243. ) Values placed in the segment register positions of the data structure must
  1244.   be valid for real mode. That is, the values must be paragraph addresses, not
  1245.   protected mode selectors.
  1246.  
  1247. ) The target real mode handler must return with the stack in the same state
  1248.   as when it was called. This means that the real mode code may switch stacks
  1249.   while it is running, but must return on the same stack that it was called
  1250.   on and must return with an IRET.
  1251.  
  1252. ) When this function returns, the real mode register data structure will
  1253.   contain the values that were returned by the real mode interrupt handler.
  1254.   The CS:IP and SS:SP values will be unmodified in the data structure.
  1255.  
  1256. ) It is the caller's responsibility to remove any parameters that were pushed
  1257.   on the protected mode stack.
  1258.  
  1259. 2.17 - Function 0301h - Call Real Mode Procedure With Far Return Frame:
  1260. -----------------------------------------------------------------------
  1261.  
  1262. Simulates a FAR CALL to a real mode procedure. The called procedure must
  1263. return by executing a RETF instruction.
  1264.  
  1265. In:
  1266.   AX     = 0301h
  1267.   BH     = must be 0
  1268.   CX     = number of words to copy from the protected mode stack to the real
  1269.            mode stack
  1270.   ES:EDI = selector:offset of real mode register data structure in the
  1271.            following format:
  1272.  
  1273.            Offset  Length  Contents
  1274.            00h     4       EDI
  1275.            04h     4       ESI
  1276.            08h     4       EBP
  1277.            0ch     4       reserved, ignored
  1278.            10h     4       EBX
  1279.            14h     4       EDX
  1280.            18h     4       ECX
  1281.            1ch     4       EAX
  1282.            20h     2       CPU status flags
  1283.            22h     2       ES
  1284.            24h     2       DS
  1285.            26h     2       FS
  1286.            28h     2       GS
  1287.            2ah     2       IP
  1288.            2ch     2       CS
  1289.            2eh     2       SP
  1290.            30h     2       SS
  1291.  
  1292. Out:
  1293.   if successful:
  1294.   ES:EDI = selector offset of modified real mode register data structure
  1295.  
  1296.   if failed:
  1297.   AX     = error code:
  1298.            8012h - linear memory unavailable (stack)
  1299.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1300.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1301.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1302.  
  1303. Notes:
  1304. ) The CS:IP in the real mode register data structure specifies the address of
  1305.   the real mode procedure to call.
  1306.  
  1307. ) If the SS:SP fields in the real mode register data structure are zero, a
  1308.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1309.   will be set to the specified values before the procedure is called.
  1310.  
  1311. ) Values placed in the segment register positions of the data structure must
  1312.   be valid for real mode. That is, the values must be paragraph addresses, not
  1313.   protected mode selectors.
  1314.  
  1315. ) The target real mode procedure must return with the stack in the same state
  1316.   as when it was called. This means that the real mode code may switch stacks
  1317.   while it is running, but must return on the same stack that it was called
  1318.   on and must return with a RETF and should not clear the stack of any
  1319.   parameters that were passed to it on the stack.
  1320.  
  1321. ) When this function returns, the real mode register data structure will
  1322.   contain the values that were returned by the real mode procedure. The CS:IP
  1323.   and SS:SP values will be unmodified in the data structure.
  1324.  
  1325. ) It is the caller's responsibility to remove any parameters that were pushed
  1326.   on the protected mode stack.
  1327.  
  1328. 2.18 - Function 0302h - Call Real Mode Procedure With IRET Frame:
  1329. -----------------------------------------------------------------
  1330.  
  1331. Simulates a FAR CALL with flags pushed on the stack to a real mode procedure.
  1332. The real mode procedure must return by executing an IRET instruction or a
  1333. RETF 2.
  1334.  
  1335. In:
  1336.   AX     = 0301h
  1337.   BH     = must be 0
  1338.   CX     = number of words to copy from the protected mode stack to the real
  1339.            mode stack
  1340.   ES:EDI = selector:offset of real mode register data structure in the
  1341.            following format:
  1342.  
  1343.            Offset  Length  Contents
  1344.            00h     4       EDI
  1345.            04h     4       ESI
  1346.            08h     4       EBP
  1347.            0ch     4       reserved, ignored
  1348.            10h     4       EBX
  1349.            14h     4       EDX
  1350.            18h     4       ECX
  1351.            1ch     4       EAX
  1352.            20h     2       CPU status flags
  1353.            22h     2       ES
  1354.            24h     2       DS
  1355.            26h     2       FS
  1356.            28h     2       GS
  1357.            2ah     2       IP
  1358.            2ch     2       CS
  1359.            2eh     2       SP
  1360.            30h     2       SS
  1361.  
  1362. Out:
  1363.   if successful:
  1364.   ES:EDI = selector offset of modified real mode register data structure
  1365.  
  1366.   if failed:
  1367.   AX     = error code:
  1368.            8012h - linear memory unavailable (stack)
  1369.            8013h - physical memory unavailable (stack) (DPMI 1.0 only)
  1370.            8014h - backing store unavailable (stack) (DPMI 1.0 only)
  1371.            8021h - invalid value (CX too large) (DPMI 1.0 only)
  1372.  
  1373. Notes:
  1374. ) The CS:IP in the real mode register data structure specifies the address of
  1375.   the real mode procedure to call.
  1376.  
  1377. ) If the SS:SP fields in the real mode register data structure are zero, a
  1378.   real mode stack will be provided by the host. Otherwise the real mode SS:SP
  1379.   will be set to the specified values before the procedure is called.
  1380.  
  1381. ) The flags specified in the real mode register data structure will be put on
  1382.   the real mode procedure's IRET frame. The procedure will be called with the
  1383.   interrupt and trace flags clear.
  1384.  
  1385. ) Values placed in the segment register positions of the data structure must
  1386.   be valid for real mode. That is, the values must be paragraph addresses, not
  1387.   protected mode selectors.
  1388.  
  1389. ) The target real mode procedure must return with the stack in the same state
  1390.   as when it was called. This means that the real mode code may switch stacks
  1391.   while it is running, but must return on the same stack that it was called
  1392.   on and must return with an IRET or discard the flags from the stack with a
  1393.   RETF 2 and should not clear the stack of any parameters that were passed to
  1394.   it on the stack.
  1395.  
  1396. ) When this function returns, the real mode register data structure will
  1397.   contain the values that were returned by the real mode procedure. The CS:IP
  1398.   and SS:SP values will be unmodified in the data structure.
  1399.  
  1400. ) It is the caller's responsibility to remove any parameters that were pushed
  1401.   on the protected mode stack.
  1402.  
  1403. 2.19 - Function 0303h - Allocate Real Mode Callback Address:
  1404. ------------------------------------------------------------
  1405.  
  1406. Returns a unique real mode segment:offset, known as a "real mode callback",
  1407. that will transfer control from real mode to a protected mode procedure.
  1408. Callback addresses obtained with this function can be passed by a protected
  1409. mode program to a real mode application, interrupt handler, device driver,
  1410. TSR, etc... so that the real mode program can call procedures within the
  1411. protected mode program.
  1412.  
  1413. In:
  1414.   AX     = 0303h
  1415.   DS:ESI = selector:offset of protected mode procedure to call
  1416.   ES:EDI = selector:offset of 32h byte buffer for real mode register data
  1417.            structure to be used when calling the callback routine.
  1418.  
  1419. Out:
  1420.   if successful:
  1421.   CX:DX  = segment:offset of real mode callback
  1422.  
  1423.   if failed:
  1424.   AX     = error code:
  1425.            8015h - callback unavailable
  1426.  
  1427. Notes:
  1428. ) A descriptor may be allocated for each callback to hold the real mode SS
  1429.   descriptor. Real mode callbacks are a limited system resource. A client
  1430.   should release a callback that it is no longer using.
  1431.  
  1432. 2.20 - Function 0304h - Free Real Mode Callback Address:
  1433. --------------------------------------------------------
  1434.  
  1435. Releases a real mode callback address that was previously allocated with the
  1436. Allocate Real Mode Callback Address function (0303h).
  1437.  
  1438. In:
  1439.   AX     = 0304h
  1440.   CX:DX  = segment:offset of real mode callback to be freed
  1441.  
  1442. Out:
  1443.   if failed:
  1444.   AX     = error code:
  1445.            8024h - invalid callback address
  1446.  
  1447. Notes:
  1448. ) Real mode callbacks are a limited system resource. A client should release
  1449.   any callback that it is no longer using.
  1450.  
  1451. 2.21 - Function 0305h - Get State Save/Restore Addresses:
  1452. ---------------------------------------------------------
  1453.  
  1454. Returns the address of two procedures used to save and restore the state of
  1455. the current task's registers in the mode (protected or real) which is not
  1456. currently executing.
  1457.  
  1458. In:
  1459.   AX     = 0305h
  1460.  
  1461. Out:
  1462.   always successful:
  1463.   AX     = size of buffer in bytes required to save state
  1464.   BX:CX  = segment:offset of real mode routine used to save/restore state
  1465.   SI:EDI = selector:offset of protected mode routine used to save/restore
  1466.            state
  1467.  
  1468. Notes:
  1469. ) The real mode segment:offset returned by this function should be called
  1470.   only in real mode to save/restore the state of the protected mode registers.
  1471.   The protected mode selector:offset returned by this function should be
  1472.   called only in protected mode to save/restore the state of the real mode
  1473.   registers.
  1474.  
  1475. ) Both of the state save/restore procedures are entered by a FAR CALL with the
  1476.   following parameters:
  1477.  
  1478.   AL       = 0 to save state
  1479.            = 1 to restore state
  1480.   ES:(E)DI = (selector or segment):offset of state buffer
  1481.  
  1482.   The state buffer must be at least as large as the value returned in AX by
  1483.   INT 31h function 0305h. The state save/restore procedures do not modify any
  1484.   registers. DI must be used for the buffer offset in real mode, EDI must be
  1485.   used in protected mode.
  1486.  
  1487. ) Some DPMI hosts and VCPI/XMS/raw will not require the state to be saved,
  1488.   indicating this by returning a buffer size of zero in AX. In such cases,
  1489.   that addresses returned by this function can still be called, although they
  1490.   will simply return without performing any useful function.
  1491.  
  1492. ) Clients do not need to call the state save/restore procedures before using
  1493.   INT 31h function 0300h, 0301h, or 0302h. The state save/restore procedures
  1494.   are provided for clients that use the raw mode switch services only.
  1495.  
  1496. 2.22 - Function 0306h - Get Raw Mode Switch Addresses:
  1497. ------------------------------------------------------
  1498.  
  1499. Returns addresses that can be called for low level mode switching.
  1500.  
  1501. In:
  1502.   AX     = 0306h
  1503.  
  1504. Out:
  1505.   always successful:
  1506.   BX:CX  = segment:offset of real to protected mode switch procedure
  1507.   SI:EDI = selector:offset of protected to real mode switch procedure
  1508.  
  1509. Notes:
  1510. ) The real mode segment:offset returned by this function should be called
  1511.   only in real mode to switch to protected mode. The protected mode
  1512.   selector:offset returned by this function should be called only in protected
  1513.   mode to switch to real mode.
  1514.  
  1515. ) The mode switch procedures are entered by a FAR JMP to the appropriate
  1516.   address with the following parameters:
  1517.  
  1518.   AX    = new DS
  1519.   CX    = new ES
  1520.   DX    = new SS
  1521.   (E)BX = new (E)SP
  1522.   SI    = new CS
  1523.   (E)DI = new (E)IP
  1524.  
  1525.   The processor is placed into the desired mode, and the DS, ES, SS, (E)SP,
  1526.   CS, and (E)IP registers are updated with the specific values. In other
  1527.   words, execution of the client continues in the requested mode at the
  1528.   address provided in registers SI:(E)DI. The values specified to be placed
  1529.   into the segment registers must be appropriate for the destination mode.
  1530.   That is, segment addresses for real mode, and selectors for protected mode.
  1531.  
  1532.   The values in EAX, EBX, ECX, EDX, ESI, and EDI after the mode switch are
  1533.   undefined. EBP will be preserved across the mode switch call so it can be
  1534.   used as a pointer. FS and GS will contain zero after the mode switch.
  1535.  
  1536.   If interrupts are disabled when the mode switch procedure is invoked, they
  1537.   will not be re-enabled by the host (even temporarily).
  1538.  
  1539. ) It is up to the client to save and restore the state of the task when using
  1540.   this function to switch modes. This requires the state save/restore
  1541.   procedures whose addresses can be obtained with INT 31h function 0305h.
  1542.  
  1543. 2.23 - Function 0400h - Get Version:
  1544. ------------------------------------
  1545.  
  1546. Returns the version of the DPMI Specification implemented by the DPMI host.
  1547. The client can use this information to determine what functions are available.
  1548.  
  1549. In:
  1550.   AX     = 0400h
  1551.  
  1552. Out:
  1553.   always successful:
  1554.   AH     = DPMI major version as a binary number (VCPI/XMS/raw returns 1)
  1555.   AL     = DPMI minor version as a binary number (VCPI/XMS/raw returns 0)
  1556.   BX     = flags:
  1557.            Bits    Significance
  1558.            0       0 = host is 16bit (PMODE never runs under one of these)
  1559.                    1 = host is 32bit
  1560.            1       0 = CPU returned to V86 mode for reflected interrupts
  1561.                    1 = CPU returned to real mode for reflected interrupts
  1562.            2       0 = virtual memory not supported
  1563.                    1 = virtual memory supported
  1564.            3-15    reserved
  1565.   CL     = processor type:
  1566.            03h = 80386
  1567.            04h = 80486
  1568.            05h = 80586
  1569.            06h-ffh = reserved
  1570.   DH     = current value of master PIC base interrupt (low 8 IRQs)
  1571.   DL     = current value of slave PIC base interrupt (high 8 IRQs)
  1572.  
  1573. Notes:
  1574. ) The major and minor version numbers are binary, not BCD. So a DPMI 0.9
  1575.   implementation would return AH as 0 and AL as 5ah (90).
  1576.  
  1577. 2.24 - Function 0500h - Get Free Memory Information:
  1578. ----------------------------------------------------
  1579.  
  1580. Returns information about the amount of available memory. Since DPMI clients
  1581. could be running in a multitasking environment, the information returned by
  1582. this function should be considered advisory.
  1583.  
  1584. In:
  1585.   AX     = 0500h
  1586.   ES:EDI = selector:offset of 48 byte buffer
  1587.  
  1588. Out:
  1589.   if successful:
  1590.   buffer is filled with the following information:
  1591.  
  1592.   if failed:
  1593.   AX     = error code:
  1594.            8010h - internal resource unavailable (stack) (XMS only)
  1595.  
  1596.   Offset  Length  Contents
  1597.   00h     4       Largest available free block in bytes
  1598.   04h     2ch     Other fields only supplied by DPMI
  1599.  
  1600. Notes:
  1601. ) Only the first field of the structure is guaranteed to contain a valid
  1602.   value. Any fields that are not supported by the host will be set to -1
  1603.   (0ffffffffh) to indicate that the information is not available.
  1604.  
  1605. 2.25 - Function 0501h - Allocate Memory Block:
  1606. ----------------------------------------------
  1607.  
  1608. Allocates a block of extended memory.
  1609.  
  1610. In:
  1611.   AX     = 0501h
  1612.   BX:CX  = size of block in bytes (must be non-zero)
  1613.  
  1614. Out:
  1615.   if successful:
  1616.   BX:CX  = linear address of allocated memory block
  1617.   SI:DI  = memory block handle (used to resize and free block)
  1618.  
  1619.   if failed:
  1620.   AX     = error code:
  1621.            8010h - internal resource unavailable (stack) (XMS only)
  1622.            8012h - linear memory unavailable (DPMI 1.0/VCPI only)
  1623.            8013h - physical memory unavailable
  1624.            8014h - backing store unavailable (DPMI 1.0 only)
  1625.            8016h - handle unavailable (DPMI 1.0/XMS only)
  1626.            8021h - invalid value (BX:CX = 0)
  1627.  
  1628. Notes:
  1629. ) The allocated block is guaranteed to have at least paragraph alignment.
  1630.  
  1631. ) This function does not allocate any descriptors for the memory block. It is
  1632.   the responsibility of the client to allocate and initialize any descriptors
  1633.   needed to access the memory with additional function calls.
  1634.  
  1635. ) The allocations by this function could be paragraph, kilobyte, or page
  1636.   aligned. That is, the value you request could be rounded up to the next
  1637.   paragraph, kilobyte, or page value.
  1638.  
  1639. 2.26 - Function 0502h - Free Memory Block:
  1640. ------------------------------------------
  1641.  
  1642. Frees a memory block previously allocated with the Allocate Memory Block
  1643. function (0501h).
  1644.  
  1645. In:
  1646.   AX     = 0502h
  1647.   SI:DI  = memory block handle
  1648.  
  1649. Out:
  1650.   if failed:
  1651.   AX     = error code:
  1652.            8010h - internal resource unavailable (stack) (XMS only)
  1653.            8023h - invalid handle
  1654.  
  1655. Notes:
  1656. ) No descriptors are freed by this call. It is the client's responsibility to
  1657.   free any descriptors that it previously allocated to map the memory block.
  1658.   Descriptors should be freed before memory blocks.
  1659.  
  1660. 2.27 - Function 0503h - Resize Memory Block:
  1661. --------------------------------------------
  1662.  
  1663. Changes the size of a memory block previously allocated with the Allocate
  1664. Memory Block function (0501h).
  1665.  
  1666. In:
  1667.   AX     = 0503h
  1668.   BX:CX  = new size of block in bytes (must be non-zero)
  1669.   SI:DI  = memory block handle
  1670.  
  1671. Out:
  1672.   BX:CX  = new linear address of memory block
  1673.   SI:DI  = new memory block handle
  1674.  
  1675.   if failed:
  1676.   AX     = error code:
  1677.            8010h - internal resource unavailable (stack) (XMS only)
  1678.            8012h - linear memory unavailable (DPMI 1.0/VCPI only)
  1679.            8013h - physical memory unavailable
  1680.            8014h - backing store unavailable (DPMI 1.0 only)
  1681.            8016h - handle unavailable (DPMI 1.0/XMS only)
  1682.            8021h - invalid value (BX:CX = 0)
  1683.            8023h - invalid handle
  1684.  
  1685. Notes:
  1686. ) After this function returns successfully, the previous handle for the memory
  1687.   block is invalid and should not be used anymore.
  1688.  
  1689. ) It is the client's responsibility to update any descriptors that map the
  1690.   memory block with the new linear address after resizing the block.
  1691.  
  1692. 2.28 - Function 050Ah - Get Memory Block Size and Base:
  1693. -------------------------------------------------------
  1694.  
  1695. Returns the size and base of a memory block that was previously allocated
  1696. with the Allocate Memory Block function (0501h).
  1697.  
  1698. In:
  1699.   AX     = 050ah
  1700.   SI:DI  = memory block handle
  1701.  
  1702. Out:
  1703.   if successful:
  1704.   BX:CX  = linear address of memory block
  1705.   SI:DI  = size of memory block (bytes)
  1706.  
  1707.   if failed:
  1708.   AX     = error code:
  1709.            8010h - internal resource unavailable (stack) (XMS only)
  1710.            8023h - invalid handle
  1711.  
  1712. Notes:
  1713. ) This function is not present under DPMI 0.9.
  1714.  
  1715. 2.29 - Function 0900h - Get and Disable Virtual Interrupt State:
  1716. ----------------------------------------------------------------
  1717.  
  1718. Disables the virtual interrupt flag and returns the previous state of it.
  1719.  
  1720. In:
  1721.   AX     = 0900h
  1722.  
  1723. Out:
  1724.   always successful:
  1725.   AL     = 0 if virtual interrupts were previously disabled
  1726.   AL     = 1 if virtual interrupts were previously enabled
  1727.  
  1728. Notes:
  1729. ) AH is not changed by this function. Therefore the previous state can be
  1730.   restored by simply executing another INT 31h.
  1731.  
  1732. ) A client that does not need to know the prior interrupt state can execute
  1733.   the CLI instruction rather than calling this function. The instruction may
  1734.   be trapped by a DPMI host and should be assumed to be very slow.
  1735.  
  1736. 2.30 - Function 0901h - Get and Enable Virtual Interrupt State:
  1737. ---------------------------------------------------------------
  1738.  
  1739. Enables the virtual interrupt flag and returns the previous state of it.
  1740.  
  1741. In:
  1742.   AX     = 0901h
  1743.  
  1744. Out:
  1745.   always successful:
  1746.   AL     = 0 if virtual interrupts were previously disabled
  1747.   AL     = 1 if virtual interrupts were previously enabled
  1748.  
  1749. Notes:
  1750. ) AH is not changed by this function. Therefore the previous state can be
  1751.   retstored by simply executing another INT 31h.
  1752.  
  1753. ) A client that does not need to know the prior interrupt state can execute
  1754.   the STI instruction rather than calling this function. The instruction may
  1755.   be trapped by a DPMI host and should be assumed to be very slow.
  1756.  
  1757. 2.31 - Function 0902h - Get Virtual Interrupt State:
  1758. ----------------------------------------------------
  1759.  
  1760. Returns the current state of the virtual interrupt flag.
  1761.  
  1762. In:
  1763.   AX     = 0902h
  1764.  
  1765. Out:
  1766.   always successful:
  1767.   AL     = 0 if virtual interrupts are disabled
  1768.   AL     = 1 if virtual interrupts are enabled
  1769.  
  1770. Notes:
  1771. ) This function should be used in preference to the PUSHF instruction to
  1772.   examine the interrupt flag, because the PUSHF instruction returns the
  1773.   physical interrupt flag rather than the virtualized interrupt flag. On some
  1774.   DPMI hosts, the physical interrupt flag will always be enabled, even when
  1775.   the hardware interrupts are not being passed through to the client.
  1776.  
  1777. 2.32 - Function FFFFh - Special Fluffy Magical Function:
  1778. --------------------------------------------------------
  1779.  
  1780. Does special fluffy magical things.
  1781.  
  1782. In:
  1783.   AX     = ffffh
  1784.  
  1785. Out:
  1786.   if successful:
  1787.   AX     = 1234h (normal fluffy magical number)
  1788.   BX     = 56ijh (special fluffy magical number)
  1789.   CX     = 89abh (nothing really special)
  1790.   DX     = cdefh (again, just a boring number)
  1791.   EX     = return value from beyond
  1792.   FX     = an acronym for 'effects'
  1793.   GX     = huh?
  1794.   HX     = size of special fluffy magical buffer
  1795.  
  1796.   if failed:
  1797.   AX     = error code:
  1798.            8001h - get a grip on reality!
  1799.  
  1800. Notes:
  1801. ) The special fluffy magical buffer must not exceed the special fluffy magical
  1802.   constant in size, which is defined in the special fluffy magical place.
  1803.  
  1804. ) Well, maybe it exists... Maybe if you try calling it many many many many
  1805.   many many many many times in a row it will succeed.
  1806.  
  1807. ------------------------------------------------------------------------------
  1808. 3 - Miscellenaous:
  1809. ------------------
  1810.  
  1811.   Some final things about PMODE, including some low level tech info if you are
  1812. just curious.
  1813.  
  1814. 3.0 - Updates:
  1815. --------------
  1816.  
  1817.   Here are the changes from any previous versions of PMODE 3.0.
  1818.  
  1819. PMODE 3.0:
  1820. ) First release of PMODE 3.0.
  1821.  
  1822. PMODE 3.01:
  1823. ) Slightly optimized VCPI/XMS/raw mode switching routines.
  1824.  
  1825. ) Fixed bug with INT 31h translation functions 0300h, 0301h, and 0302h not
  1826.   returning correct flags in the register structure.
  1827.  
  1828. ) Fixed bug with software INT redirection calls clearing the interrupt flag.
  1829.  
  1830. PMODE 3.02:
  1831. ) Decreased VCPI mode switching free stack space requirement to 32 bytes.
  1832.  
  1833. PMODE 3.03:
  1834. ) Fixed real mode INT 15h in raw mode, now always returns with the carry flag
  1835.   clear as it should.
  1836.  
  1837. PMODE 3.04:
  1838. ) Fixed a stupid bug with INT 31h AX=03??h requiring the high word of ECX to
  1839.   be clear that someone pointed out to me.
  1840.  
  1841. ) Added (actually just documented) low level access to PMODE's internal real
  1842.   mode and protected mode stacks.
  1843.  
  1844. 3.1 - Glossary:
  1845. ---------------
  1846.  
  1847. Bottom up allocation - A method of extended memory allocation which relies on
  1848.   control blocks specifying the start of free extended memory. This is the
  1849.   VDISK extended memory allocation scheme.
  1850.  
  1851. Client - A program which uses DPMI INT 2fh and INT 31h services to run in
  1852.   protected mode.
  1853.  
  1854. CPL, Current Privilege Level - The privilege level of the currently executing
  1855.   code.
  1856.  
  1857. Descriptor - An 8 byte structure which defines a segment type, its base
  1858.   address and limit, and the type of access allowed to it.
  1859.  
  1860. DPL, Descriptor Privilege Level - The privilege level of a descriptor.
  1861.   Descriptor protection is based on certain rules of the CPL and DPL of a
  1862.   descriptor that code may want to access.
  1863.  
  1864. DPMI, DOS Protected Mode Interface - An interface for protected mode DOS
  1865.   programs to manage memory, interrupts, exceptions, debugging registers, and
  1866.   coprocessor emulation in a well behaved manner which allows them to coexist
  1867.   with other protected mode programs and operating systems.
  1868.  
  1869. Exception - An interrupt that occurs because of some violation of protection
  1870.   rules.
  1871.  
  1872. Extended memory - Memory which lies above the 1M boundary and can only be
  1873.   addressed in protected mode.
  1874.  
  1875. GDT, Global Descriptor Table - A descriptor table which can contain many types
  1876.   of descriptors besides the regular code and data descriptors. This can
  1877.   include TSS descriptors and LDT descriptors.
  1878.  
  1879. Host - A program which provides DPMI protected mode services.
  1880.  
  1881. IDT, Interrupt Descriptor Table - A descriptor table which contains the
  1882.   gate descriptors to the handlers for the 256 interrupts.
  1883.  
  1884. LDT, Local Descriptor Table - A descriptor table which usually contains all
  1885.   the descriptors of a particular task. Each task in a 386 multitasking system
  1886.   can have its own LDT whereas there is only one GDT for the entire system.
  1887.  
  1888. Linear memory - Address space rather than actual physical RAM of ROM.
  1889.  
  1890. Page - A 4k chunk of memory. The 80386 can map any 4k chunk of physical memory
  1891.   to any linear address. There are also some protection rules that can apply
  1892.   to pages, such as read-only, or privilege level checking on access.
  1893.  
  1894. Page Directory - Sort of a master page table which maps page tables instead of
  1895.   pages.
  1896.  
  1897. Page Table - A 4k table containing 1024 entries for pages. Each page table
  1898.   maps 4 megabytes of linear memory to physical memory.
  1899.  
  1900. Physical memory - The actual physical memory present in a system.
  1901.  
  1902. Privilege level - A numeric value representing the freedom of system access
  1903.   and how much protection applies to code. This value ranges from
  1904.   0 (most free (godlike)) to 3 (least free (lowly slave)).
  1905.  
  1906. RPL, Requestor Privilege Level - The privilege level code requests for a
  1907.   specific selector access. It is contained in the low two bits of the
  1908.   selector.
  1909.  
  1910. Segment - A specific linear chunk of memory. In real mode, segments are
  1911.   limited to the first megabyte of memory and are always 64k in length. In
  1912.   protected mode, a segment can start anywhere in the entire 4 gigabyte
  1913.   address space of the 80386 and can be that long.
  1914.  
  1915. Selector - An index in protected mode into a descriptor table. Selectors are
  1916.   used in place of segments in protected mode in the segment registers.
  1917.  
  1918. Top down allocation - A method of extended memory management which relies on
  1919.   the BIOS INT 15h function 88h. A program which needs to allocate extended
  1920.   memory will hook INT 15h and return a smaller extended memory size. The
  1921.   program is then free to use the memory between the previous top of extended
  1922.   memory and what it returns as the top of extended memory without worrying
  1923.   about other programs overwriting its extended memory.
  1924.  
  1925. TSS, Task State Segment - A special memory structure used in task switching
  1926.   and protection.
  1927.  
  1928. V86 mode - Actually it is protected mode, running at a privilege level of 3.
  1929.   Segment registers are used in the same manner as in real mode, with segment
  1930.   addresses rather than selectors. The advantage is that paging and other
  1931.   protected tasks can be active, which includes other V86 mode tasks. The
  1932.   disadvantage is that it is slower than real mode.
  1933.  
  1934. VCPI, Virtual Control Program Interface - The predecessor to DPMI. VCPI
  1935.   extends the EMS interface to allow DOS programs to run in protected mode
  1936.   in the presence of EMS emulators or other 80386 control programs.
  1937.  
  1938. Virtual memory - Extra memory beyond the actual physical memory present in a
  1939.   system. There is not really any more physical memory in the system, but an
  1940.   operating system or DPMI host can give that illusion by swapping the
  1941.   contents of physical memory to and from a disk and mapping that physical
  1942.   memory to different linear addresses.
  1943.  
  1944. XMS, eXtended Memory Specification - A handle based extended memory management
  1945.   interface.
  1946.  
  1947. 3.2 - Differences between modes:
  1948. --------------------------------
  1949.  
  1950. Some differences between DPMI, VCPI, XMS, and raw protected mode:
  1951.  
  1952. ) DPMI:
  1953.     Client descriptors reside in a LDT.
  1954.   VCPI/XMS/raw:
  1955.     Client descriptors reside in the GDT.
  1956.  
  1957. ) DPMI:
  1958.     Code runs at CPL 3.
  1959.   VCPI/XMS/raw:
  1960.     Code runs at CPL 0. (Much faster)
  1961.  
  1962. ) DPMI/VCPI:
  1963.     Real mode calls are executed in V86 mode.
  1964. ) XMS/raw:
  1965.     Real mode calls are executed in real mode. (Much faster)
  1966.  
  1967. ) DPMI/VCPI:
  1968.     Paging is enabled.
  1969.   XMS/raw:
  1970.     Paging is disabled. (Not really very much faster, but what the hell)
  1971.  
  1972. ) DPMI:
  1973.     IRET(D) and POPF(D) may not affect the interrupt flag. PUSHF(D) may not
  1974.     store the interrupt flag.
  1975.   VCPI/XMS/raw:
  1976.     IRET(D) and POPF(D) affect the real interrupt flag. PUSHF(D) stores the
  1977.     real interrupt flag.
  1978.  
  1979. ) DPMI:
  1980.     INTs 1Ch, 23h, and 24h from real mode are sent to protected mode first.
  1981.     This means if a protected mode handler is installed for these interrupts,
  1982.     it will get control.
  1983. ) VCPI/XMS/raw:
  1984.     DPMI dox are not too clear on the method these interrupts are called in.
  1985.     Callbacks I would guess. But I am too lazy to investigate. And frankly, I
  1986.     don't give a shit. So the VCPI/XMS/raw kernel does not support this.
  1987.  
  1988. ) DPMI:
  1989.     Seperates exceptions from other low interrupts and IRQs. That is, an
  1990.     exception 8 would never erroneously go to the handler for IRQ 0.
  1991. ) VCPI/XMS/raw:
  1992.     Hey, exceptions are bad, you should not be getting them in the first
  1993.     place. Reprogramming the interrupt controllers or running the client code
  1994.     at a lower privilege is not worth the slowdown for me.
  1995.  
  1996. ) DPMI:
  1997.     Theoretically, DPMI may refuse a request to set a segment limit to 4G.
  1998.     I have not yet found a DPMI that will refuse this. They all do protection
  1999.     at the paging level. And a high limit is necessary for flat mode and
  2000.     negative offsets.
  2001. ) VCPI/XMS/raw:
  2002.     There is no protection, no segment limit or base address will ever be
  2003.     denied.
  2004.  
  2005. ) DPMI:
  2006.     Memory allocation is almost always page granular, but not necessarily.
  2007.   VCPI:
  2008.     Memory allocation is page granular (4k chunks).
  2009.   XMS:
  2010.     Memory allocation is kilobyte granular.
  2011.   raw:
  2012.     Memory allocation is paragraph granular.
  2013.  
  2014. ) DPMI/VCPI:
  2015.     Low memory linear addresses may or may not be the actual physical
  2016.     addresses. Extended memory addresses are almost sure not to be.
  2017.   XMS/raw:
  2018.     All linear addresses are physical addresses.
  2019.  
  2020. 3.3 - Notes:
  2021. ------------
  2022.  
  2023.   Here are some misc and low level technical details about PMODE and some
  2024. points I want to emphasize. Some of them may seem very obscure, with no real
  2025. need to list. But for the sake of thorough documentation, they are here:
  2026.  
  2027. ) In protected mode, ESP must always be the stack pointer. Meaning, even if
  2028.   using a 16bit stack segment, the high word of ESP MUST be 0.
  2029.  
  2030. ) When calling the raw mode switching routine to switch into protected mode,
  2031.   you must supply the full ESP and EIP. Even if the stack or code segments
  2032.   being switched to are 16bit.
  2033.  
  2034. ) If the call to init protected mode was from a segment other than PMODE_TEXT
  2035.   under DPMI, and a descriptor can not be allocated for that code segment,
  2036.   immediate termination results. But this should never happen. A DPMI host
  2037.   that can not supply even one descriptor to its protected mode clients defies
  2038.   logic. But for the sake of covering all possible screw-ups, this condition
  2039.   is checked for.
  2040.  
  2041. ) DPMI 1.0/VCPI/XMS/raw will reload any segment registers for which the
  2042.   descriptor is changed through an INT 31h function. DPMI 0.9 does not.
  2043.   (Actually it does, through pushing and then popping any segment registers
  2044.   it uses. But it is not guaranteed to reload any or all of them).
  2045.  
  2046. ) DPMI 1.0/VCPI/XMS/raw will zero any segment registers freed with INT 31
  2047.   function 0001h. DPMI 0.9 may or may not.
  2048.  
  2049. ) I dont know about DPMI with respect to reloading or freeing a selector which
  2050.   is currently loaded into SS, but the VCPI/XMS/raw system will not reload or
  2051.   zero SS. You should not be modifying your stack or code descriptor as you
  2052.   are using it. This could be bad, even if the INT 31h were handled through a
  2053.   task gate (which would be slow).
  2054.  
  2055. ) Remember that DPMI 0.9 does not return error codes as DPMI 1.0/VCPI/XMS/raw
  2056.   do.
  2057.  
  2058. ) Reasons for calls to real mode executing in actual real mode rather than
  2059.   V86 mode (XMS/raw):
  2060.   ) V86 call system can not be used under VCPI very successfully. (Yes, VCPI
  2061.     runs its real mode in V86. But VCPI MUST be in control in this case.)
  2062.   ) Real mode runs faster than V86 mode.
  2063.   ) INT 15h and XMS extended memory functions will work.
  2064.   ) Other protected mode programs that run DOS functions in real mode will
  2065.     work.
  2066.   ) It is faster to switch between protected/real mode than protected/V86.
  2067.  
  2068. ) Use LAR to find out the current CPL for setting descriptor access right.
  2069.  
  2070. ) You must always set the present bit when setting descriptor access rights.
  2071.  
  2072. ) Under the VCPI/XMS/raw system, the AVL bit of descriptors is used to keep
  2073.   track of free and used descriptors. The value you pass for this bit when
  2074.   setting descriptor access rights will be ignored.
  2075.  
  2076. ) When switching modes using the raw switching routines, make sure there is
  2077.   some space on both stacks (real and protected). Specific DPMI requirements
  2078.   may vary, but 32 bytes is enough for VCPI/XMS/raw.
  2079.  
  2080. ) In protected mode, remember to use IRETD, not IRET. When DPMI documentation
  2081.   refers to using IRET, it is actually referring to the 32bit version of the
  2082.   instruction under 32bit systems, which is IRETD.
  2083.  
  2084. ) Remember that free memory information is just advisory. A TSR or another
  2085.   task in a multitasking system might grab some memory in between a call to
  2086.   INT 31h function 0500h and INT 31h function 0501h, even if you disable
  2087.   interrupts.
  2088.  
  2089. ) The _pm_? variables are not checked for validity. So don't set them outside
  2090.   reasonable bounds. For example, don't ask for 20h real mode stacks of size
  2091.   1000h paragraphs. This is two megabytes of real mode stack space. This is
  2092.   way too much, considering that all real mode available low memory
  2093.   encompasses 640k.
  2094.  
  2095. ) You should allocate memory in large blocks. Memory space is subject to
  2096.   fragmentation. Although you can help the situation a little under VCPI by
  2097.   setting a high number of page tables. This will not increase the physical
  2098.   memory available, but it will increase the address space available to put
  2099.   that memory into linear chunks.
  2100.  
  2101. ) I tried to balance clean, well designed code, with size and speed. True,
  2102.   some things are not as absolutely optimal as they can be. But the source is
  2103.   right here. Very clean and commented. If you truly need those last ounces of
  2104.   speed, feel free to modify it (this does not free you from the obligation of
  2105.   crediting me for it).
  2106.  
  2107. ) I can not control what DPMI does. But under XMS/raw, code in protected mode
  2108.   runs at the fastest speed possible. That is, there is no privilege checking
  2109.   to get in the way. No exception will rip control away from sensitive
  2110.   instructions. Not even paging, with its memory references every time a page
  2111.   table entry is not found in the TLB. Under VCPI, all of this applies except
  2112.   the paging. Which really isn't that bad.
  2113.  
  2114. ) Under VCPI, free memory information is validated in function 0500h by
  2115.   actually allocating that memory and releasing it before passing the
  2116.   information to your program. This because under some multitasking systems,
  2117.   the VCPI function for getting the memory available may return information
  2118.   for the whole system. While the multitasking system may impose allocation
  2119.   limits on the specific task your code is part of.
  2120.  
  2121. ) Under VCPI/XMS/raw, INT 31h function 0500h will return only the first field
  2122.   of the buffer set. All the other fields will be set to 0ffffffffh.
  2123.  
  2124. ) Under VCPI/XMS/raw, an allocate descriptor INT 31h function 0000h called
  2125.   with CX = 0 will return error 8021h. DPMI dox dont state this, and I dont
  2126.   know if DPMI returns an error on CX = 0.
  2127.  
  2128. ) INT 31h functions 0300h, 0301h, and 0302h will always inform you if there is
  2129.   not enough real mode stack space. But and IRQ or INT redirection can not.
  2130.   In this case, the PC speaker will be turned on, and the machine will be
  2131.   hung. This is better than allowing it to overrun data below it with
  2132.   unpredictable results. And hey, I dont need no stinkin debug code cluttering
  2133.   up my nice and pretty extender. I just need it to tell me in case something
  2134.   like this happenes. If you want debug code, go and hack it in yourself.
  2135.  
  2136. ) DPMI dox dont state this, but the alias descriptor INT 31h function 000ah
  2137.   creates is always an expand-up and writeable data descriptor. No matter what
  2138.   type the source descriptor is.
  2139.  
  2140. ) You should limit yourself to allocating as few individual memory blocks as
  2141.   possible. Under XMS, there is usually a strict limit on how many blocks can
  2142.   be allocated (normally 32).
  2143.  
  2144. ) DPMI dox state that the field between EBP and EBX should be zero upon an
  2145.   INT 31h function 0300h, but is ignored by functions 0301h and 0302h. That is
  2146.   just a stupid typo, the field will be ignored by function 0300h.
  2147.  
  2148. ) Under XMS an extra 15 bytes will be allocated for possible aligning of the
  2149.   XMS memory block on a paragraph. Though an XMS block will probably already
  2150.   be aligned on at least a paragraph boundary, this is not defined in the XMS
  2151.   standard. And to keep the possibility of problems at nil, this is done.
  2152.  
  2153. ) Be aware that memory allocation functions under XMS use real mode calls and
  2154.   real mode stack space defined with _pm_rmstacklen and _pm_rmstacks. If there
  2155.   is not enough stack space for the call to the real mode XMS driver, error
  2156.   code 8010h (resource unavailable) will be returned.
  2157.  
  2158. ) If an XMS memory lock fails, which is used in memory allocation functions,
  2159.   error 8010h will be returned. A memory lock failure is not due to memory not
  2160.   being available. But rather, some internal XMS crap. But it should never
  2161.   happen anyway.
  2162.  
  2163. ) The raw system checks both INT 15h and the VDISK low to high extended memory
  2164.   allocation scheme to get its available extended memory area.
  2165.  
  2166. ) The raw system allocates extended memory on an as-needed basis from the top
  2167.   down. INT 15h function 88h is hooked and the total amount of memory
  2168.   allocated using the kernel function 0501h is subtracted from the amount of
  2169.   memory returned from the previous INT 15h handler. This is so that you can
  2170.   execute other protected mode programs from within your programs and they
  2171.   will have extended memory available (if you left any).
  2172.  
  2173. ) A protected mode IRQ handler or real mode callback must return on the same
  2174.   stack it was called with.
  2175.  
  2176. ) A real mode routine called with functions 0300h, 0301h, or 0302h must return
  2177.   on the same stack it was called with.
  2178.  
  2179. ) You should make no assumptions about the low memory protected mode data area
  2180.   needed by PMODE. It can range from very small to very large. And if a DPMI
  2181.   host is present, it is unpredictable.
  2182.  
  2183. ) Make sure you do not access, read or write, extended memory outside the
  2184.   blocks you allocate. Even if there is no physical memory there, you will
  2185.   probably get exceptions under DPMI/VCPI.
  2186.  
  2187. ) When setting descriptor access rights, remember that the B bit of stack
  2188.   descriptors determines whether PUSHes and POPs use SP (B=0) or ESP (B=1).
  2189.  
  2190. ) If you enable interrupts in a callback, you MUST assume DS is no longer
  2191.   valid. Even if you are sure your callback will not be re-entered. This is
  2192.   because PMODE uses the same DS selector for ALL real mode callbacks.
  2193.  
  2194. ) The reserved field between EBP and EBX in the register structure used during
  2195.   a callback is used by PMODE to preserve the high word of ESP for real mode.
  2196.  
  2197. ) You should assume the INT 31h extended memory functions to be slow.
  2198.   Especially under VCPI, where a call has to be made to the VCPI server for
  2199.   each 4k of memory allocated or freed, and two calls for each 4k verified.
  2200.  
  2201. ) Under PMODE, software INT redirection calls only pass back the carry,
  2202.   parity, aux, zero, sign, and overflow flags from the real mode interrupt
  2203.   handler.
  2204.  
  2205. ) When using the raw mode switching routines, keep in mind that they use some
  2206.   stack space on both the real mode and protected mode stacks. Never set the
  2207.   destination stack to the same location in memory as the stack being switched
  2208.   from.
  2209.  
  2210. ------------------------------------------------------------------------------
  2211. 3.4 - Final word:
  2212. -----------------
  2213.  
  2214.   I like this latest PMODE a lot. For an extender, it is clean, solid, fast,
  2215. and small. It is not limited to assembly code. It does not need control at
  2216. startup, but may be initialized at any time. It can be turned into basically
  2217. any type of extender. It can work with high level languages. You will probably
  2218. also like it because it is free, and the source code is provided. The DPMI
  2219. interface assures portability and long life. Enjoy protected mode, and
  2220. remember the credits.
  2221.  
  2222.                                                 L8r...
  2223.                                                 Tran...
  2224.  
  2225.